

#include "Functie.h"
#define nrOperatii 16

/*precedenta operatori:
    0 +
    1 -
    2 *
    3 /
    4 ^
    5 asin
    6 acos
    7 atan
    8 actg
    9 sin
    10 cos
    11 tan
    12 ctg
    13 log
    14 ln
    15 exp
*/

Functie::Functie(const char *expresieIntrodusa)
  {
    (*this).expresie=new char[strlen(expresieIntrodusa)+1];
    strcpy((*this).expresie,expresieIntrodusa);       
    (*this).radacina = creezArboreleBinar(0, strlen((*this).expresie));
  }
Nod *Functie::creezArboreleBinar(int limitaInferioara, int limitaSuperioara)
{
    int i, pozitieMinima, operatiaMinima, operatieNoua;
    int prioritate;
    Nod *rezultat = 0;

    operatiaMinima = nrOperatii; pozitieMinima = -1;
    prioritate = 0;
    for (i = limitaInferioara; i < limitaSuperioara; i++)
    {
        operatieNoua = prioritate * nrOperatii;
        if((*this).expresie[i]=='('){
					prioritate++;
					operatieNoua=operatiaMinima;
				}
				else if((*this).expresie[i]==')'){
					prioritate--;
					operatieNoua=operatiaMinima;
				}
				else if((*this).expresie[i]=='+'){
					operatieNoua++;operatieNoua--;
				}
				else if((*this).expresie[i]=='-'){
					operatieNoua+=1;
				}
				else if((*this).expresie[i]=='*'){
					operatieNoua+=2;
				}
				else if((*this).expresie[i]=='/'){
					operatieNoua+=3;
				}
				else if((*this).expresie[i]=='^'){
					operatieNoua+=4;
				}
				else if((*this).expresie[i]=='s'){
					operatieNoua = !strncmp((*this).expresie + i, "sin", 3) ? operatieNoua + 9: operatiaMinima;
				}
				else if((*this).expresie[i]=='c'){
					if (!strncmp((*this).expresie + i, "cos", 3)) operatieNoua += 10;
             else if (!strncmp((*this).expresie + i, "ctg", 3)) operatieNoua += 12;
                     else operatieNoua = operatiaMinima;
				}
				else if((*this).expresie[i]=='t'){
					if(!strncmp((*this).expresie + i, "tan", 3)) operatieNoua += 11;
            else operatieNoua = operatiaMinima;
				}
				else if((*this).expresie[i]=='a'){
					if (!strncmp((*this).expresie + i, "asin", 4)) operatieNoua += 5;
             else if (!strncmp((*this).expresie + i, "acos", 4)) operatieNoua += 6;
             else if (!strncmp((*this).expresie + i, "atan", 4)) operatieNoua += 7;
             else if (!strncmp((*this).expresie + i, "actg", 4)) operatieNoua += 8;
             else operatieNoua = operatiaMinima;
				}
				else if((*this).expresie[i]=='l'){
					if (!strncmp((*this).expresie + i, "log", 3)) operatieNoua += 13;
             else if (!strncmp((*this).expresie + i, "ln", 2)) operatieNoua += 14;
                     else operatieNoua = operatiaMinima;
  			}
				else if((*this).expresie[i]=='e'){
					if (!strncmp((*this).expresie + i, "exp", 3)) operatieNoua += 15;
             else operatieNoua = operatiaMinima;   
				}
				else
					operatieNoua=operatiaMinima;	 
   
       verificPrecedenta(operatieNoua, i, &operatiaMinima, &pozitieMinima);
    }

    if (operatiaMinima < nrOperatii)
    {
        if(operatiaMinima==0)
					rezultat = new Plus();
				else if(operatiaMinima==1)
					rezultat = new Minus();
				else if(operatiaMinima==2)
					rezultat = new Inmultit();
				else if(operatiaMinima==3)
					rezultat = new Impartit();
				else if(operatiaMinima==4)
					rezultat = new Putere();
				else if(operatiaMinima==5)
					rezultat = new ASin();
				else if(operatiaMinima==6)
					rezultat = new ACos();
				else if(operatiaMinima==7)
					rezultat = new ATan();
				else if(operatiaMinima==8)
					rezultat = new ACtg();
				else if(operatiaMinima==9)
					rezultat = new Sin();
				else if(operatiaMinima==10)
					rezultat = new Cos();
				else if(operatiaMinima==11)
					rezultat = new Tangenta();
				else if(operatiaMinima==12)
					rezultat = new Cotan();
				else if(operatiaMinima==13)
					rezultat = new Logaritm();
				else if(operatiaMinima==14)
					rezultat = new LogaritmN();
				else 
					rezultat = new Exp();

        if (operatiaMinima < 5)
        {
            rezultat->setFStang(creezArboreleBinar(limitaInferioara, pozitieMinima));
            rezultat->setFDrept(creezArboreleBinar(pozitieMinima + 1, limitaSuperioara));
        }
        else
        {
            int nrBeg, nrEnd = 1;
            for (nrBeg = 0; limitaInferioara + nrBeg < strlen((*this).expresie) && (*this).expresie[limitaInferioara + nrBeg] != '('; nrBeg++)
                ;
            if (limitaInferioara + nrBeg > strlen((*this).expresie))
                nrEnd = nrBeg = 0;
            if (operatiaMinima == 13)
            {
                int pozMid;

                for (pozMid = nrBeg + 1; (*this).expresie[limitaInferioara + pozMid] != ','; pozMid++)
                    ;
                rezultat->setFStang(creezArboreleBinar(limitaInferioara + nrBeg + 1, limitaInferioara + pozMid));
                rezultat->setFDrept(creezArboreleBinar(limitaInferioara + pozMid + 1, limitaSuperioara - nrEnd));
            }
            else
            {
                rezultat->setFStang(creezArboreleBinar(limitaInferioara + nrBeg + 1, limitaSuperioara - nrEnd));
                rezultat->setFDrept(0);
            }
        }
    }
    else
    {
        while (limitaInferioara < limitaSuperioara && (*this).expresie[limitaInferioara] == ' ') limitaInferioara++;
        while (limitaSuperioara > limitaInferioara && (*this).expresie[limitaSuperioara - 1] == ' ') limitaSuperioara--;
        if ((*this).expresie[limitaInferioara] == '(')
        {
            while ((*this).expresie[limitaInferioara] == '(')
            {
                limitaInferioara++; limitaSuperioara--;
            }
            return creezArboreleBinar(limitaInferioara, limitaSuperioara);
        }
        if ((*this).expresie[limitaInferioara] == '-')
        {
            rezultat = new Inmultit();
            rezultat->setFStang(new Constanta(-1));
            rezultat->setFDrept(creezArboreleBinar(limitaInferioara + 1, limitaSuperioara));
        }
        if ((*this).expresie[limitaInferioara] == 'x' && (limitaSuperioara - limitaInferioara == 1))
            rezultat = new Necunoscuta();
        else
        {
            char *aux = new char[limitaSuperioara - limitaInferioara + 1];
            int i;

            for (i = limitaInferioara; i < limitaSuperioara; i++)
                aux[i - limitaInferioara] = (*this).expresie[i];
            aux[i - limitaInferioara] = '\0';

            rezultat = new Constanta(atof(aux));
	    
            delete aux;
            return rezultat;
        }
    }

    return rezultat;
}

void Functie::verificPrecedenta(int precedentaNoua, int pozitieNoua, int *precedentaVeche, int *pozitieVeche)
{
    if (precedentaNoua < *precedentaVeche)
        {
            *pozitieVeche = pozitieNoua;
            *precedentaVeche = precedentaNoua;
        }
}

long double Functie::calculezValoare(long double x)
{
    (*this).radacina->setX(x);
    return (*this).radacina->calcul();
}

char *Functie::toString()
{
    return (*this).radacina->toString();
}

char *Functie::derivata()
{
    return (*this).radacina->derivare();
}

long double Functie::calculezDerivata(long double x)
{
    (*this).radacina->setX(x);
    return (*this).radacina->calculDerivata();
}

Functie::~Functie()
{
    delete (*this).radacina;
}

